package com.example.demo.service.impl;

import com.example.demo.exception.AccessDeniedException;
import com.example.demo.exception.BusinessException;
import com.example.demo.exception.CustomException;
import com.example.demo.exception.ResourceNotFoundException;
import com.example.demo.model.entity.achievement.ResearchPaper;
import com.example.demo.model.entity.audit.AuditRecord;
import com.example.demo.model.entity.relation.TeacherStudentRelation;
import com.example.demo.model.entity.user.User;
import com.example.demo.model.enums.AuditResult;
import com.example.demo.model.enums.PaperStatusEnum;
import com.example.demo.model.enums.UserTypeEnum;
import com.example.demo.model.vo.StudentPaperVO;
import com.example.demo.model.vo.StudentUpdateVO;
import com.example.demo.mapper.TeacherStudentRelationMapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.mapper.ResearchPaperMapper;
import com.example.demo.mapper.AuditRecordMapper;
import com.example.demo.security.SecurityUtils;
import com.example.demo.service.TeacherManageService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class TeacherManageServiceImpl implements TeacherManageService {

    private final TeacherStudentRelationMapper relationMapper;
    private final UserMapper userMapper;
    private final ResearchPaperMapper paperMapper;
    private final AuditRecordMapper auditRecordMapper;
    private final SecurityUtils securityUtils;

    // ========== 基础角色检查 ==========
    private boolean isAdmin(User user) {
        return UserTypeEnum.ADMIN.equals(user.getUserType());
    }

    private boolean isTeacher(User user) {
        return UserTypeEnum.TEACHER.equals(user.getUserType());
    }

    private boolean isStudent(User user) {
        return UserTypeEnum.STUDENT.equals(user.getUserType());
    }

    // ========== 核心业务方法 ==========
    @Override
    @Transactional(readOnly = true)
    public List<User> getRelatedStudents(Long teacherId) {
        if (teacherId == null) {
            throw new BusinessException("无法获取当前教师ID");
        }

        List<TeacherStudentRelation> relations = relationMapper.findByTeacherId(teacherId);
        if (relations == null || relations.isEmpty()) {
            return Collections.emptyList();
        }

        List<Long> studentIds = relations.stream()
                .map(TeacherStudentRelation::getStudentId)
                .collect(Collectors.toList());

        List<User> students = userMapper.findByUserIds(studentIds);

        return students.stream()
                .filter(User::isStudent)
                .peek(User::validateDataIntegrity)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public PageInfo<StudentPaperVO> getStudentPapers(Long teacherId, int pageNum, int pageSize) {
        List<Long> studentIds = relationMapper.findByTeacherId(teacherId).stream()
                .map(TeacherStudentRelation::getStudentId)
                .collect(Collectors.toList());

        if (studentIds.isEmpty()) {
            return new PageInfo<>(Collections.emptyList());
        }

        PageHelper.startPage(pageNum, pageSize);
        List<ResearchPaper> papers = paperMapper.findBySubmitUserIds(studentIds);

        return new PageInfo<>(papers.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList()));
    }

    @Override
    @Transactional
    public void auditPaper(Long paperId, Long teacherId, AuditResult result, String comment) {
        // 1. 获取论文并验证存在性
        ResearchPaper paper = paperMapper.findById(paperId)
                .orElseThrow(() -> new ResourceNotFoundException("论文不存在: " + paperId));

        log.debug("开始审核论文 - 论文ID: {}, 当前状态: {}, 提交者ID: {}",
                paperId, paper.getStatus(), paper.getSubmitUserId());

        // 2. 验证教师权限
        validateTeacherPaperPermission(teacherId, paper.getSubmitUserId());

        // 3. 验证论文状态
        validatePaperStatusForAudit(paper.getStatus());

        // 4. 转换并更新状态
        PaperStatusEnum newStatus = convertAuditResultToStatus(result);
        updatePaperStatus(paper, newStatus);

        // 5. 记录审核日志
        createAuditRecord(paperId, teacherId, result, comment);

        log.info("论文审核完成 - 审核人ID: {}, 论文ID: {}, 结果: {}, 新状态: {}",
                teacherId, paperId, result, newStatus);
    }

    /**
     * 验证教师是否有权限审核该学生提交的论文
     */
    private void validateTeacherPaperPermission(Long teacherId, Long studentId) {
        if (!relationMapper.existsByTeacherIdAndStudentId(teacherId, studentId)) {
            log.warn("权限验证失败 - 教师ID: {} 无权审核学生ID: {} 的论文", teacherId, studentId);
            throw new AccessDeniedException("您无权审核此学生提交的论文");
        }
    }

    /**
     * 验证论文当前状态是否允许审核
     */
    private void validatePaperStatusForAudit(Integer currentStatus) {
        if (currentStatus != PaperStatusEnum.SUBMITTED.getCode()) {
            log.warn("状态验证失败 - 当前论文状态: {} 不允许审核",
                    PaperStatusEnum.fromCode(currentStatus));
            throw new IllegalStateException("论文当前状态不允许审核");
        }
    }

    /**
     * 更新论文状态
     */
    private void updatePaperStatus(ResearchPaper paper, PaperStatusEnum newStatus) {
        paper.setStatus(newStatus.getCode());
        paper.setUpdateTime(LocalDateTime.now());
        if (paperMapper.update(paper) != 1) {
            throw new OptimisticLockingFailureException("论文状态更新失败");
        }
    }

    /**
     * 创建审核记录
     */
    private void createAuditRecord(Long paperId, Long teacherId, AuditResult result, String comment) {
        log.debug("尝试插入审核记录 - paperId:{}, teacherId:{}, result:{}, comment:{}",
                paperId, teacherId, result, comment);

        AuditRecord record = AuditRecord.builder()
                .achievementId(paperId)
                .auditUserId(teacherId)
                .auditResult(result)
                .auditComment(comment.length() > 500 ? comment.substring(0, 497) + "..." : comment)
                .build();

        try {
            auditRecordMapper.insert(record);
        } catch (DataAccessException e) {
            log.error("完整SQL参数: achievement_id={}, audit_user_id={}, audit_result={}, audit_comment={}",
                    paperId, teacherId, result, comment);
            throw e;
        }
    }

    @Override
    public PaperStatusEnum convertAuditResultToStatus(AuditResult result) {
        switch (result) {
            case APPROVED:
                return PaperStatusEnum.APPROVED;
            case REJECTED:
                return PaperStatusEnum.REJECTED;
            case PENDING:
                return PaperStatusEnum.PENDING_REVIEW;
            default:
                throw new IllegalArgumentException("未知的审核结果类型: " + result);
        }
    }

    @Override
    @Transactional(readOnly = true)
    public PageInfo<AuditRecord> getAuditRecords(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return new PageInfo<>(auditRecordMapper.findByAuditUserId(securityUtils.getCurrentUserId()));
    }

    @Override
    @Transactional(readOnly = true)
    public PageInfo<AuditRecord> getAuditRecords(int pageNum, int pageSize, AuditResult result) {
        PageHelper.startPage(pageNum, pageSize);
        return new PageInfo<>(auditRecordMapper.findByAuditUserIdAndResult(
                securityUtils.getCurrentUserId(), result));
    }

    @Override
    @Transactional
    public void removeStudentRelation(Long studentId) {
        Long teacherId = securityUtils.getCurrentUserId();

        TeacherStudentRelation relation = relationMapper.findByTeacherIdAndStudentId(teacherId, studentId)
                .orElseThrow(() -> new AccessDeniedException("无权限操作该学生"));

        User student = userMapper.findByUserId(studentId)
                .orElseThrow(() -> new ResourceNotFoundException("学生不存在"));
        validateStudentForOperation(student);

        if (hasPendingAudits(studentId)) {
            throw new IllegalStateException("存在未完成的论文审核，无法解除关联");
        }

        relationMapper.deleteByTeacherIdAndStudentId(teacherId, studentId);
        log.info("师生关系解除 - 教师ID: {}, 学生ID: {}", teacherId, studentId);
    }

    @Override
    @Transactional(readOnly = true)
    public boolean hasPendingAudits(Long studentId) {
        String statuses = Arrays.asList(
                PaperStatusEnum.SUBMITTED.getCode(),
                PaperStatusEnum.REVISING.getCode()
        ).stream().map(String::valueOf).collect(Collectors.joining(","));

        return paperMapper.existsBySubmitUserIdAndStatusIn(studentId, statuses);
    }

    @Override
    @Transactional
    public void updateStudentInfo(Long studentId, StudentUpdateVO updateVO) {
        Long teacherId = securityUtils.getCurrentUserId();

        if (!relationMapper.existsByTeacherIdAndStudentId(teacherId, studentId)) {
            throw new AccessDeniedException("无权限修改该学生信息");
        }

        User student = getUser(studentId);
        updateStudentFields(student, updateVO);
        userMapper.update(student);

        log.info("学生信息更新 - 教师ID: {}, 学生ID: {}, 更新字段: {}",
                teacherId, studentId, updateVO);
    }

    // ========== 私有工具方法 ==========
    private User getUser(Long userId) {
        return userMapper.findByUserId(userId)
                .orElseThrow(() -> new ResourceNotFoundException("用户不存在: " + userId));
    }

    private void validateStudentForOperation(User student) {
        if (!isStudent(student)) {
            throw new IllegalArgumentException("只能操作学生账号");
        }
        if (!student.isEnabled()) {
            throw new IllegalStateException("该账号已被禁用");
        }
    }

    private void updateStudentFields(User student, StudentUpdateVO updateVO) {
        student.setName(updateVO.getName());
        student.setPhone(updateVO.getPhone());
        student.setEmail(updateVO.getEmail());
        student.setUpdateTime(LocalDateTime.now());
    }

    private StudentPaperVO convertToVO(ResearchPaper paper) {
        PaperStatusEnum status = PaperStatusEnum.fromCode(paper.getStatus());
        return StudentPaperVO.builder()
                .paperId(paper.getId())
                .paperTitle(paper.getPaperTitle())
                .journal(paper.getJournal())
                .issue(paper.getIssue())
                .volume(paper.getVolume())
                .pageRange(paper.getPageRange())
                .authors(paper.getAuthors())
                .firstAuthor(paper.getFirstAuthor())
                .correspondingAuthor(paper.getCorrespondingAuthor())
                .publishDate(paper.getPublishDate())
                .impactFactor(paper.getImpactFactor())
                .paperLink(paper.getPaperLink())
                .status(status)
                .statusDescription(status.getDescription())
                .submitTime(paper.getCreateTime())
                .studentName(getStudentName(paper.getSubmitUserId()))
                .build();
    }

    private String getStudentName(Long studentId) {
        return userMapper.findByUserId(studentId)
                .map(User::getName)
                .orElse("未知学生");
    }

    // ========== 新增扩展方法 ==========
    @Override
    @Transactional(readOnly = true)
    public PageInfo<ResearchPaper> searchStudentPapers(Long studentId, String keyword,
                                                       PaperStatusEnum status, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Integer statusCode = status != null ? status.getCode() : null;
        List<ResearchPaper> papers = paperMapper.searchPapers(
                keyword, null, null, statusCode,
                null, null, 0, Integer.MAX_VALUE
        );
        return new PageInfo<>(papers);
    }

    @Override
    @Transactional(readOnly = true)
    public ResearchPaper getPaperDetail(Long paperId) {
        ResearchPaper paper = paperMapper.findById(paperId)
                .orElseThrow(() -> new ResourceNotFoundException("论文不存在"));
        paper.setStatusEnum(PaperStatusEnum.fromCode(paper.getStatus()));
        return paper;
    }
}